﻿using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking.Proximity;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using System.Runtime.InteropServices.WindowsRuntime;
using LightOMator.IO;


namespace LightOMator.Bluetooth
{
    public class BluetoothConnection
    {
        public enum ConnectionState
        {
            NotConnected, Paired, Connected
        }
        public EventHandler<ConnectionState> ConnectionStateChanged;

        private const string _deviceName = "SeeedBTSlave";
        private PeerInformation _peer;
        private StreamSocket _socket;
        private Enough.Async.AsyncLock _asyncLock = new Enough.Async.AsyncLock();


        private bool _isPaired;
        public bool IsPaired
        {
            get { return _isPaired; }
        }

        private bool _isConnected;
        public bool IsConnected
        {
            get { return _isConnected; }
        }

        private bool _isWriting;
        private string _lastDataStr;

        public async Task<bool> Connect()
        {
            //if (true) return true;
            try
            {
                using (await _asyncLock.LockAsync())
                {
                    if (_peer == null)
                    {
                        PeerFinder.AlternateIdentities["Bluetooth:Paired"] = "";
                        var peers = await PeerFinder.FindAllPeersAsync();
                        PeerInformation peer = peers.FirstOrDefault(p => _deviceName.Equals(p.DisplayName));
                        if (peer == null)
                        {
                            return false;
                        }
                        _peer = peer;
                        _isPaired = true;
                        if (ConnectionStateChanged != null)
                        {
                            ConnectionStateChanged(this, ConnectionState.Paired);
                        }
                    }
                    if (_socket != null)
                    {
                        _socket.Dispose();
                    }
                    _socket = new StreamSocket();
                    await _socket.ConnectAsync(_peer.HostName, remoteServiceName: "1");
                    _isConnected = true;
                    if (ConnectionStateChanged != null)
                    {
                        ConnectionStateChanged(this, ConnectionState.Connected);
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("unable to connect: " + ex);
                if (ConnectionStateChanged != null)
                {
                    ConnectionStateChanged(this, ConnectionState.NotConnected);
                }
                return false;
            }
        }

        private async Task DoStuffAsync()
        {
            await Task.Delay(500);
        }


        public async Task<bool> WriteString(string dataStr)
        {
            if (!_isConnected)
            {
                return false;
            }
            if (_isWriting)
            {
                _lastDataStr = dataStr;
                return false;
            }
            try
            {
                using (await _asyncLock.LockAsync())
                {
                    _isWriting = true;
                    await _socket.WriteString(dataStr);
                    dataStr = _lastDataStr;
                    if (dataStr != null)
                    {
                        _lastDataStr = null;
                        await Task.Delay(250);
                        await _socket.WriteString(dataStr);
                    }
                }
                return true;
            }
            catch (Exception)
            {
                _isConnected = false;
                if (ConnectionStateChanged != null)
                {
                    ConnectionStateChanged(this, ConnectionState.NotConnected);
                }
            }
            finally
            {
                _isWriting = false;
            }
            await Connect();
            return false;
        }
    }
}
